// The Editor Presenter

/// <reference path="../typings/jquery/jquery.d.ts" />
/// <reference path="../typings/jquery/jqueryui.d.ts" />

// import UI interfaces
import I = require("./Interfaces");

// import the dictionary module
import Dic = require("../MiddleLayer/Execution/Dictionary");

// import command module
import Cmd = require("../MiddleLayer/Execution/Commands");

// import parser module
import Parser = require("../MiddleLayer/Parser/CommandParser");

// import message box
import MsgBox = require("./MessageBox");


// class editor
export class Editor implements I.IEditor {

    // flag if in edit mode
    private mEditMode: boolean;

    // reference to the shown command
    private mShownCommand: Cmd.UserCommand;

    // reference to the Karel's dictionary
    private mDictionary: Dic.Dictionary;

    // UI dependencies
    private mUIDictionary: I.IDictionary;

    // constructor
    public constructor() {
        this.mDictionary = Dic.Dictionary.Instance;
        this.mShownCommand = null;
        this.mUIDictionary = null;

        // build the control
        this.mEditMode = false;
        this.BuildControl();
        this.LayoutControl();
    }

    // sets the UI dependencies
    public SetDependencies(uiDictionary: I.IDictionary) {
        this.mUIDictionary = uiDictionary;
    }

    // shows the command
    public ShowCommand(commandName: string): void {
        if (this.mEditMode == false) {
            // if clearing command
            if (commandName == null || this.mDictionary.IsSystemCommand(commandName)) {
                this.mShownCommand = null;
                $("#idCommandPane > pre").text("");
                //$("#idEditCommand").attr("disabled", "disabled");
                $("#idDiagramPane").html("");
                this.LayoutControl();
                return;
            }


            var command = this.mDictionary.GetUserCommandByName(commandName);

            if (command == null)
                return;

            this.mShownCommand = command;
            if (this.mShownCommand == null) {
                $("#idCommandPane > pre").text("");
                //$("#idEditCommand").attr("disabled", "disabled");
                $("#idDiagramPane").html("");
                this.LayoutControl();
            }
            else {
                $("#idCommandPane > pre").text(this.mShownCommand.GetSourceCode());
                //$("#idEditCommand").removeAttr("disabled");
                $("#idDiagramPane").html(this.mShownCommand.GenerateCardDiagram());
                this.LayoutControl();
            }
        }
    }

    // invokes editation of this command
    public EditCommand(commandName: string): void {
        // shows the command
        this.ShowCommand(commandName);

        // enters the edit mode
        this.EnterEditMode();

        // focus the editor
        $("#idEditorInput").focus();
        (<any>$("#idEditorInput")).selectRange(0, 0);

    }

    // starts the new command
    public NewCommand(): void {
        // if edit mode is running, exit
        if (this.mEditMode == true)
            return;

        // show empty command
        this.ShowCommand(null);

        // switch to the edit mode
        this.EnterEditMode();

        // set default text, focus editor and select range for entering the new command name
        $("#idEditorInput").val("NOVY PRIKAZ\nKONEC");
        $("#idEditorInput").focus();
        (<any>$("#idEditorInput")).selectRange(0, 11);
    }

    // edits the current command
    public EditCurrentCommand(): void {
        // if edit mode is running, exit
        if (this.mEditMode == true)
            return;

        // if no command shown, exit
        if (this.mShownCommand == null)
            return;

        // enters the edit mode
        this.EnterEditMode();

        // focus the editor
        $("#idEditorInput").focus();
    }

    // saves the current command
    public SaveCommand(): void {
        // if edit mode is not running, exit
        if (this.mEditMode == false)
            return;

        // try to parse the command
        if (this.ParseCommand($("#idEditorInput").val()) == true) {
            // if successful, leave edit mode
            this.LeaveEditMode();

            // refresh the dictionary and select the current command
            if (this.mUIDictionary != null && this.mShownCommand != null) {
                this.mUIDictionary.RefreshCommands(this.mShownCommand.GetName());

            }
        }
    }

    // cancels edit mode 
    public CancelEditingCommand(): void {
        // if edit mode is not running, exit
        if (this.mEditMode == false)
            return;

        this.LeaveEditMode();

        // clear the editing control
        $(window).focus();
        $("#idEditorInput").val("");

        // refresh the dictionary and select the current command
        if (this.mUIDictionary != null) {
            this.mUIDictionary.RefreshCommands(null);
        }
    }


    // returns whether we are in edit mode
    public IsEditMode(): boolean {
        return this.mEditMode;
    }

    // builds the control
    private BuildControl(): void {
        // control settings
        $("#idTopEditorToolbar button").button();
        $("#idBottomEditorToolbar button").button();

        //$("#idEditCommand").attr("disabled", "disabled");
        //$("#idSaveCommand").attr("disabled", "disabled");
        //$("#idCancelCommand").attr("disabled", "disabled");

        //$("#idEditorInput").attr("readonly", "true");
        $("#idEditorInput").css("background-color", "#feeebd");

        // command handlers
        var that = this;
        $("#idNewCommand").click(function (event) {
            that.NewCommand();
        });

        $("#idEditCommand").click(function (event) {
            if (that.mShownCommand != null) {
                that.EditCommand(that.mShownCommand.GetName());
            }
        });

        $("#idSaveCommand").click(function (event) {
            that.SaveCommand();
        });

        $("#idCancelCommand").click(function (event) {
            that.CancelEditingCommand();
        });
    }

    public LayoutControl(): void {
        // layout the toolbars and the editor main pane
        var height = $("#idTopEditorToolbar").outerHeight();

        if (!this.mEditMode) {
            height = 0;
        }
        $("#idBottomEditorToolbar").outerHeight(height);

        height = $("#idEditor").innerHeight() - $("#idTopEditorToolbar").outerHeight() - $("#idBottomEditorToolbar").outerHeight();
        $("#idEditorWrapper").outerHeight(height);

        var width = $("#idEditorWrapper").innerWidth();

        // choose the editable view
        var height = $("#idEditorWrapper").innerHeight();
        if (this.mEditMode) {
            $("#idBottomEditorToolbar").show();
            $("#idEditorEditPane").outerHeight(height);
            $("#idEditorViewPane").outerHeight(0);
            $("#idEditorViewPane").hide();
                        
        } else {
            $("#idBottomEditorToolbar").hide();
            $("#idEditorViewPane").outerHeight(height);
            $("#idEditorViewPane").show();
            $("#idEditorEditPane").outerHeight(0);
            $("#idEditorViewPane").outerWidth(width);

            height = $("#idEditorViewPane").innerHeight();

            $("#idEditorViewPane").outerHeight(height);
            $("#idDiagramPane").outerHeight(height);

            width = Math.floor($("#idEditorViewPane").innerWidth());
            width = Math.floor(width - Math.ceil($("#idCommandPane").outerWidth()) - 1);
            $("#idDiagramPane").outerWidth(width);
        }       
    }

    // prepares UI to edit mode
    private EnterEditMode() {
        this.mEditMode = true;
        //$("#idNewCommand").attr("disabled", "disabled");
        //$("#idEditCommand").attr("disabled", "disabled");
        //$("#idSaveCommand").removeAttr("disabled");
        //$("#idCancelCommand").removeAttr("disabled");
        //$("#idEditorInput").removeAttr("readonly");
        $("#idEditorInput").css("background-color", "white");

        // add shown command to the editor
        if (this.mShownCommand != null) {
            $("#idEditorInput").val(this.mShownCommand.GetSourceCode());
        }

        this.LayoutControl();
    }

    // prepares UI when leaving edit mode
    private LeaveEditMode() {
        this.mEditMode = false;
        //$("#idNewCommand").removeAttr("disabled");
        //$("#idEditCommand").removeAttr("disabled");
        //$("#idSaveCommand").attr("disabled", "disabled");
        //$("#idCancelCommand").attr("disabled", "disabled");
        //$("#idEditorInput").attr("readonly", "true");
        $("#idEditorInput").css("background-color", "#feeebd");
        this.LayoutControl();
    }

    // method for parsing command
    private ParseCommand(sourceCode: string): boolean {
        var parser = new Parser.CommandParser(sourceCode);
        if (parser.Parse() == true) {
            // if successful, add command
            if (parser.FinalCommand != null) {
                var userCmd = <Cmd.UserCommand>parser.FinalCommand;

                // check, if we perform UPDATE or ADD operation
                if (this.mShownCommand == null) {
                    // ADD operation
                    if (this.mDictionary.ExistsUserCommand(userCmd.GetName()) == true) {
                        MsgBox.MessageBox.Instance.ShowModal("CommandNameUsed", "Error");
                        return false;
                    }
                    else {
                        // add the command
                        this.mDictionary.AddUserCommand(userCmd);
                    }
                }
                else {
                    // UPDATE operation
                    // if the name has changed
                    if (this.mShownCommand.GetName().toLocaleLowerCase() != userCmd.GetName().toLocaleLowerCase()) {
                        // check if the old command is in use
                        if (this.mDictionary.IsCommandInUse(this.mShownCommand.GetName()) == true) {
                            MsgBox.MessageBox.Instance.ShowModal("CannotRenameCommand", "Error");
                            return false;
                        }
                    }

                    // Update the command
                    this.mDictionary.UpdateCommand(this.mShownCommand, userCmd);
                }

                // save the commands to the localStorage
                this.mDictionary.Save();

                // set the shown command to be displayed in the EditorView pane
                this.mShownCommand = userCmd;

                // set the formatted source coude
                $("#idEditorInput").val(userCmd.GetSourceCode());

                return true;
            }
            else {
                window.alert("Unexpected error. Command is NULL.");
            }
        }
        else {
            MsgBox.MessageBox.Instance.ShowModal(parser.ErrorMessage, "msgCommandError", false);
        }

        return false;
    }
}
